package com.gorkr.cronback.pattern.designPattern.factory;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronException;
import com.gorkr.cronback.pattern.matcher.BoolArrayValueMatcher;
import com.gorkr.cronback.pattern.matcher.DayOfMonthValueMatcher;
import com.gorkr.cronback.pattern.parser.DayOfMonthParser;
import com.gorkr.cronback.pattern.parser.ValueParser;

import java.util.ArrayList;
import java.util.List;


/**
 * 将parser中重复的构建matcher抽出， 构成简单工厂类。
 * 复杂对象和 对象创建解耦 （有点像builder了)， 又增加新的matcher的时候，只需要更新factory中的创建代码。
 */
public class ValueMatcherFactory {

    public BoolArrayValueMatcher buildMatcher(String value, ValueParser parser) throws Exception {

        // 计算matcer匹配列表，即哪些位置bool值应为true
        List<Integer> values = parseArray(value, parser); // 所有分钟

        if(values.size()==0){
            throw new Exception("array error");
        }

        if(parser instanceof DayOfMonthParser){
            return new DayOfMonthValueMatcher(values);
        }
        return new BoolArrayValueMatcher(values);
    }



    /**
     * 处理数组形式表达式<br>
     * 处理的形式包括：
     * <ul>
     * <li><strong>a</strong> 或 <strong>*</strong></li>
     * <li><strong>a,b,c,d</strong></li>
     * </ul>
     * @param value 子表达式值
     * @return 值列表
     */
    public List<Integer> parseArray(String value, ValueParser parser) throws Exception {
        final List<Integer> values = new ArrayList<>();

        final List<String> parts = StrUtil.split(value, StrUtil.C_COMMA); // 逗号分隔
        for(String part : parts){
            CollUtil.addAllIfNotContains(values, parseStep(part, parser)); // 添加可以匹配的值
        }
        return values;
    }

    /**
     * 处理间隔形式的表达式<br>
     * 处理的形式包括：
     * <ul>
     * <li><strong>a</strong> 或 <strong>*</strong></li>
     * <li><strong>a&#47;b</strong> 或 <strong>*&#47;b</strong></li>
     * <li><strong>a-b/2</strong></li>
     * </ul>

     * @param value 表达式值
     * @return List
     */
    private List<Integer> parseStep(String value, ValueParser parser) throws Exception {
        final List<String> parts = StrUtil.split(value, StrUtil.C_SLASH);
        int size = parts.size();

        List<Integer> results;
        if (size == 1) {// 普通形式 a 或 *
            results = parseRange(value, -1, parser);
        } else if (size == 2) {// 间隔形式
            final int step = parser.parse(parts.get(1));
            // todo : 错误处理
            results = parseRange(parts.get(0), step,parser);
        } else {
            throw new Exception("error");
        }
        return results;
    }

    /**
     * 处理表达式中范围表达式 处理的形式包括：
     * <ul>
     * <li>*</li>
     * <li>2</li>
     * <li>3-8</li>
     * <li>8-3</li>
     * <li>3-3</li>
     * </ul>
     *
     * @param value 范围表达式
     * @param step 步进
     * @return List
     */
    private  List<Integer> parseRange(String value, int step,ValueParser parser) {
        final List<Integer> results = new ArrayList<>();

        // 全部匹配形式 * 或者单个数字
        if (value.length() <= 2) {
            //根据步进的第一个数字确定起始时间，类似于 12/3则从12（秒、分等）开始
            int minValue = parser.getMin();
            if(!isMatchAllStr(value)) {
                minValue = Math.max(minValue, parser.parse(value));
            }else {
                //在全匹配模式下，如果步进不存在，表示步进为1
                if(step < 1) {
                    step = 1;
                }
            }
            if(step > 0) {
                final int maxValue = parser.getMax();
                if(minValue > maxValue) {
                    throw new CronException("Invalid value {} > {}", minValue, maxValue);
                }
                //有步进
                for (int i = minValue; i <= maxValue; i+=step) {
                    results.add(i);
                }
            } else {
                //固定时间
                results.add(minValue);
            }
            return results;
        }

        //Range模式
        List<String> parts = StrUtil.split(value, '-');
        int size = parts.size();
        if (size == 1) {// 普通值
            final int v1 = parser.parse(value);
            if(step > 0) {//类似 20/2的形式
                NumberUtil.appendRange(v1, parser.getMax(), step, results);  // 将给定范围内的整数添加到已有集合中
            }else {
                results.add(v1);
            }
        } else if (size == 2) {// range值
            final int v1 = parser.parse(parts.get(0));
            final int v2 = parser.parse(parts.get(1));
            if(step < 1) {
                //在range模式下，如果步进不存在，表示步进为1
                step = 1;
            }
            if (v1 < v2) {// 正常范围，例如：2-5
                NumberUtil.appendRange(v1, v2, step, results);
            } else if (v1 > v2) {// 逆向范围，反选模式，例如：5-2
                NumberUtil.appendRange(v1, parser.getMax(), step, results);
                NumberUtil.appendRange(parser.getMin(), v2, step, results);
            } else {// v1 == v2，此时与单值模式一致
                NumberUtil.appendRange(v1,parser.getMax(), step, results);
            }
        }
        return results;
    }

    /**
     * 是否为全匹配符<br>
     * 全匹配符指 * 或者 ?
     *
     * @param value 被检查的值
     * @return 是否为全匹配符
     */
    private static boolean isMatchAllStr(String value) {
        return (1 == value.length()) && ("*".equals(value) || "?".equals(value));
    }
}
